/*
 * @note: 辛克设置动作类
 * @date: 2015.09.12
 */
#include "globe.h"
#include "sink_setting.h"
#include "act_types.h"
#include "stepmotor.h"
#include <assert.h>
#include <malloc.h>
#include <pthread.h>
#include "feedback.h"
#include <unistd.h>
#include <string.h>
#include "udp.h"
#include "timer.h"

#define SINK_CHECK_TIME     1000

static void* sink_setting_work_thread(void *user_data);

SINK_SETTING* sink_setting_new(MH_UDP *pudp)
{
    SINK_SETTING *sink_setting = (SINK_SETTING*)malloc(sizeof (SINK_SETTING));

    memset(sink_setting, 0, sizeof(SINK_SETTING));

    sink_setting->reset = stepmotor_reset;
    sink_setting->exec = stepmotor_exec;

    sink_setting->sink_type = INVALID_SINK;
    sink_setting->ctype = LEFT_CARRIAGE;
    sink_setting->warn = 0;
    sink_setting->reset_state = SINK_RESET_COMPLETE;
    timer_stop(&sink_setting->timer);
    sink_setting->pudp = pudp;

    sink_setting->exit = FALSE;

    pthread_create(&sink_setting->th_work, NULL,
    sink_setting_work_thread, (void*)sink_setting);
    return sink_setting;
}

void sink_setting_set_zero(SINK_SETTING *sink_setting, short fzero, short bzero)
{
    assert(sink_setting != NULL);
    sink_setting->zero[0] = fzero;
    sink_setting->zero[1] = bzero;
}

void sink_setting_set_zero2(SINK_SETTING *sink_setting, short fzero, short bzero)
{
    assert(sink_setting != NULL);
    sink_setting->zero[2] = fzero;
    sink_setting->zero[3] = bzero;
}


int sink_setting_reset(SINK_SETTING *sink_setting, int ctype)
{
    assert(sink_setting != NULL);

    memset(sink_setting->pos, 0, sizeof(sink_setting->pos));

    sink_setting->reset_state = SINK_RESET;
    sink_setting->ctype = ctype;

    return 0;
}

int sink_reset(SINK_SETTING *sink_setting)
{
    assert(sink_setting != NULL);

    short find_zero[12] = { 0 };
    find_zero[8] = TRUE;
    find_zero[9] = TRUE;
#if (MH_JTCS_CAM == MAC_DS_4SINK)
    find_zero[10] = TRUE;
    find_zero[11] = TRUE;
#endif
    return sink_setting->reset(sink_setting->pudp, sink_setting->ctype, find_zero, 12);
}

int sink_setting_exec(SINK_SETTING *sink_setting, int ctype, SinkType sink_type, short des_pos)
{
    assert(sink_setting != NULL);

    if (sink_type < 0 || sink_type >= INVALID_SINK)
    {
        return 0;
    }

    sink_setting->sink_type = sink_type;
    sink_setting->ctype = ctype;
    sink_setting->des_pos[sink_type] = des_pos;

    return 0;
}

int sink_exec(SINK_SETTING *sink_setting)
{
    assert(sink_setting != NULL);

    short delta[12] = { 0 };
    short find_zero[12] = { 0 };

    int sink_type = sink_setting->sink_type;

    if (sink_type < 0 || sink_type >= INVALID_SINK)
    {
        return 0;
    }

    delta[8 + sink_type] = sink_setting->des_pos[sink_type] - sink_setting->pos[sink_type];

    return sink_setting->exec(sink_setting->pudp, sink_setting->ctype, delta, find_zero, 12);
}

void sink_setting_close(SINK_SETTING *sink_setting)
{
    assert(sink_setting);
    sink_setting->exit = TRUE;

    pthread_join(sink_setting->th_work, NULL);
    free(sink_setting);
}

int sink_check_error(MH_UDP *pudp, void *user_data)
{
    assert (user_data != NULL);
    SINK_SETTING *sink_setting = (SINK_SETTING*)user_data;

    FEEDBACK fb;
    int ret = 0;
    memset(&fb, 0, sizeof (FEEDBACK));

    ret = feedback_get_error_state(pudp, &fb, sink_setting->ctype);

    if (ret < 0)
    {
        sink_setting->warn = MH_ERROR_CAN;
        return ret;
    }

    if (fb.error.qxk)
    {
        sink_setting->warn = MH_ERROR_FSINK1;
        return -1;
    }
    else if (fb.error.hxk)
    {
        sink_setting->warn = MH_ERROR_BSINK1;
        return -1;
    }
    else if (fb.error.qxk2)
    {
        sink_setting->warn = MH_ERROR_FSINK2;
        return -1;
    }
    else if (fb.error.hxk2)
    {
        sink_setting->warn = MH_ERROR_BSINK2;
        return -1;
    }

    return 0;
}

int sink_delta(MH_UDP *pudp, void *user_data)
{
    assert (user_data != NULL);
    int ret = 0;
    SINK_SETTING *sink_setting = (SINK_SETTING*)user_data;

    short delta[12] = { 0 };
    short find_zero[12] = { 0 };

    ret = sink_check_error(pudp, user_data);

    if (ret < 0)
    {
        return ret;
    }

    delta[8] = sink_setting->zero[0];
    delta[9] = sink_setting->zero[1];
#if (MH_JTCS_CAM == MAC_DS_4SINK)
    delta[10] = sink_setting->zero[2];
    delta[11] = sink_setting->zero[3];
#endif

    ret = sink_setting->exec(sink_setting->pudp, sink_setting->ctype, delta, find_zero, 12);

    if (ret == 0)
    {
        timer_start(&sink_setting->timer, 0, SINK_CHECK_TIME, sink_check_error);
        return 0;
    }

    return ret;
}

void* sink_setting_work_thread(void *user_data)
{
    SINK_SETTING *sink_setting = (SINK_SETTING*)user_data;

    while (!sink_setting->exit)
    {
        if (sink_setting->reset_state == SINK_RESET)
        {
            /* 复位 */
            sink_reset(sink_setting);
            sink_setting->reset_state = SINK_DELTA;
            timer_start(&sink_setting->timer, 0, SINK_CHECK_TIME, sink_delta);
        }
        else if ((sink_setting->sink_type >= FSINK1) &&
            (sink_setting->sink_type < INVALID_SINK))
        {
            sink_exec(sink_setting);
            timer_start(&sink_setting->timer, 0, SINK_CHECK_TIME, sink_check_error);
            sink_setting->sink_type = INVALID_SINK;
        }

        timer_exec(sink_setting->pudp, &sink_setting->timer, sink_setting);

        usleep(2000);
    }

    pthread_exit(0);
}
